package copy.meta.impl;


import copy.mark.ParamMap;
import copy.mark.ParamMaps;
import copy.mark.clone.Clone;
import copy.meta.AbsParseMetaData;
import copy.meta.ParseEasyCopyMetaData;
import copy.pojo.IfMeta;
import copy.pojo.MethodMeta;
import copy.pojo.PropertyMeta;
import copy.scan.ScanStrategy;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.HashMap;
import java.util.Map;

/**
 * author: liziyun
 * date: 2019-9-30
 * email: root@ofo.email
 * describe: 注解解析器
 *      解析方法上的注解信息,@ParamMaps注解 和 @ParamMap注解
 *      设计模式: 模板方法模式
 */
public  class ParseEasycopyMetaDataStrategyHandler extends AbsParseMetaData {

    private static ParseEasyCopyMetaData parseEasyCopyMetaData;


    public static ParseEasyCopyMetaData getScanSingleBean(){
        if (parseEasyCopyMetaData == null){
            parseEasyCopyMetaData = new ParseEasycopyMetaDataStrategyHandler();
        }
        return parseEasyCopyMetaData;
    }

    private ParseEasycopyMetaDataStrategyHandler() {

    }

    /**
     * 解析接口的元注解信息: 封装到BeanMetaData中
     *      解析接口中方法元注解信息: 封装到BeanMethod中
     *          1. 是否存在ParamMaps注解
     *              如果有,按照注解中映射关系处理
     *              如果没有,按照方法的名称处理映射关系
     *          2. 设置EagerInstance属性
     *              表示存在目标对象,不需要new创建.
     *                  ParamMaps的判断方式,看EagerInstance属性
     *                  方法名映射的判断方式,看参数是否等于2
     *          3. 设置Clone属性
     *
     * @param clssName
     * @return
     */

    @Override
    public void solveMethodDefinition(String clssName) throws ClassNotFoundException {
        MethodMeta beanMethod  = null;
        //保存解析数据
        Map<String, MethodMeta> interfaceMedaData = interfaceMetaDataMap.get(clssName);
        //解析数据的依据
        TypeElement typeElement = ScanStrategy.easycopyMap.get(clssName);
        //获取所有的方法:解析数据的依据
        for (Element enclosedElement : typeElement.getEnclosedElements()) {
            if ( enclosedElement.getAnnotation(ParamMaps.class) == null ){
                continue;
            }

            System.out.println("parse解析方法:"+enclosedElement.getSimpleName());
            //实体
            beanMethod =  new MethodMeta();
            //注解对应关系解析
            ParamMaps paramMapsAnnotation = enclosedElement.getAnnotation(ParamMaps.class);
            //存在ParamMaps注解
            if (paramMapsAnnotation!=null){
                beanMethod.setOpenParam(true);
                if (paramMapsAnnotation.eagerInstance()){
                    beanMethod.setEagerInstance(true);
                }
            }else{//方法名自动匹配:ageByAgeAndHeightByHeight
                beanMethod.setOpenParam(false);
                //两个实例化对象，相互拷贝

            }
            //是否@Clone

            if ( typeElement.getAnnotation(Clone.class) != null ){
                beanMethod.setClone(true);
            }
            System.out.println("正在获取Params: " + paramMapsAnnotation);
            //设置注解
            beanMethod.setAnnotationMirrorList(enclosedElement.getAnnotationMirrors());
            beanMethod.setParamMapsAnnotation(paramMapsAnnotation);
            beanMethod.setMethodName(enclosedElement.getSimpleName().toString());
            interfaceMedaData.put(enclosedElement.getSimpleName().toString(),beanMethod);
        }



    }

    /**
     * key: 下标.表示第i个ParamMap
     * value: 类型转换器的全限定类名
     * @param beanMethod
     * @return
     */
    public Map<Integer,String> getTypTransforMap(MethodMeta beanMethod){
        Map<Integer,String> typeTransformMap = new HashMap<>();
        //尝试获取类型转换器
        for (AnnotationMirror annotationMirror : beanMethod.getAnnotationMirrorList()) {
            for (AnnotationValue annoValue : annotationMirror.getElementValues().values()) {
                String Str = annoValue.toString();
                String[] paramMaps = Str.split("ParamMap");
                for (int i = 1; i < paramMaps.length; i++) {//0个不要
                    String paramStr = paramMaps[i];
                    int start = paramStr.indexOf("(") +1;
                    int end = paramStr.lastIndexOf(")");
                    paramStr = paramStr.substring(start,end);
                    String[] split = paramStr.split(",");
                    for (String keyValue : split) {
                        if (keyValue.contains("TYPE_TRANSFORM")){
                            String[] twoStr = keyValue.split("=");
                            String className = twoStr[1];
                            typeTransformMap.put(i,className);
                        }
                    }
                }
            }
        }
        return typeTransformMap;
    }

    /**
     * 注解属性解析: 保存字段和字段的映射关系
     *      1. 基本属性映射: 设置targetPropertyName 和 resourcePropertyName
     *      2. 尝试获取类型转换器 TypeTransform.class
     *      3. 尝试获取拷贝类型(字段优先级 > 方法优先级)
     *      4. 尝试获取BigDecimal
     *      5. 尝试获取强制转换
     * @param beanMethod
     */
    @Override
    public void solvePropertyMappingDefinition(MethodMeta beanMethod) {
        //获取注解信息
        //Method method = beanMethod.getMethod();
        System.out.println("方法:" + beanMethod.getMethodName());
        //Class<?>[] parameterTypes = method.getParameterTypes();
        ParamMaps params = beanMethod.getParamMapsAnnotation();
        ParamMap[] entrys = params.value();
        //类型转换器
        Map<Integer, String> typTransforMap = getTypTransforMap(beanMethod);
        //根据注解信息 创建映射关系,保存到PropertyMeda中
        int index = 1;
        for (ParamMap entry : entrys) {
            String targetPropertyName = entry.targetProperty();
            String resourcePropertyName = entry.resourceProperty();

            //设置targetPropertyName 和 resourcePropertyName
            PropertyMeta property = new PropertyMeta (targetPropertyName,resourcePropertyName );
            //判断是否是IF表达式
            if (resourcePropertyName.contains("?")){
                IfMeta ifMeta = new IfMeta();
                ifMeta.setIfExpression(resourcePropertyName);
                property.setIfMeta(ifMeta);
            }
            String typeTransformClassName = typTransforMap.get(index);
            if ( typeTransformClassName != null ){
                property.setTypeTransform(typeTransformClassName);
            }
            //尝试设置BigDecimal的保留小数个数
            property.setScale( entry.scale() );
            //尝试设置BigDecimal的取舍方式
            property.setRound( entry.round() );
            //尝试获取强制转换
            if (!entry.cast().equals("")){
                property.setCast( entry.cast() );
            }//Property对象添加到BeanMethod中
            beanMethod.addPropertyMeta(property);
            index++;
        }
    }


}
